#Using R markdown

##Working with R Markdown

This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

print("Hello")
[1] "Hello"
plot(cars)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

Installing the robis package

First install the robis package. If the package is already installed, make sure the version is 2.10.0 or higher.

if (!"robis" %in% rownames(installed.packages())) {
  remotes::install_github("iobis/robis")
} else if (packageVersion("robis") < "2.10.0") {
  knitr::knit_exit()
}

We will also need the following packages:

library(robis)
library(dplyr)
library(ggplot2)
library(knitr)
library(ggtree)
library(mapview)
library(sf)
library(RColorBrewer)

eDNA data access in OBIS

In this notebook we will explore data published to OBIS using the new DNADerivedData extension. This notebook is available at https://iobis.github.io/notebook-dnaderiveddata/

Finding sequence based data

Before we fetch any occurrence data let’s first find out which datasets in OBIS are using the DNADerivedData extension. The dataset() function takes many of the same parameters as the occurrence() function, including hasextensions which allows us to limit our search to occurrences which have linked extension records of a specific type. Possible values include MeasurementOrFact and DNADerivedData.

dna_datasets <- dataset(hasextensions = "DNADerivedData")

Retrieved 51 records of approximately 51 (100%)
any(sapply(dna_datasets_geo, is.null))
[1] FALSE

#In case of error try setting: #mapviewOptions(fgb = FALSE)

Fetching sequence based data

Let’s fetch all occurrences from the PacMAN dataset by using the datasetid parameter. Alternatively, set hasextensions to DNADerivedData. Also set the extensions parameter to ensure that the nested extension records are included in the results.

pacmanID<-dna_datasets %>% filter(grepl("PacMAN", title))%>%
select(id)

occ <- occurrence(datasetid = pacmanID, extensions = "DNADerivedData", wrims = T)

Retrieved 5000 records of approximately 8612 (58%)
Retrieved 8612 records of approximately 8612 (100%)
occ

Let’s take a look at the taxonomic composition of our dataset:

occ %>%
  group_by(phylum) %>%
  summarize(species = length(unique(speciesid)), records = n()) %>%
  arrange(desc(species))

Extracting DNADerivedData records

The DNADerivedData records are currently nested within the occurrences we fetched from OBIS. To extract the extension records we can use the unnest_extension() function. Pass any fields from the occurrence table you would like to keep using the fields parameter.

Let’s take a look at some properties of the sequence records.

dna %>%
  group_by(target_gene, pcr_primer_name_forward, pcr_primer_name_reverse) %>%
  summarize(records = n()) %>%
  kable()
`summarise()` has grouped output by 'target_gene', 'pcr_primer_name_forward'. You can override using the `.groups` argument.
target_gene pcr_primer_name_forward pcr_primer_name_reverse records
18S Uni18SF Uni18SR 2625
COI mlCOIintF dgHCO2198 5987

Working with DNADerivedData records

This is a quick demo of working with sequences from the DNADerivedData extension. For the remainder of the notebook I will work with a subset of the sequence data.

dna_subset <- dna %>%
  filter(phylum == "Chordata" | phylum == "Mollusca" & !is.na(species)) %>%
  head(100)

To be able to make use of existing bioinformatics packages we first need to convert our DNA_sequence column to a DNAbin object. This can be done using as.DNAbin function from the ape (Analyses of Phylogenetics and Evolution) package.


dna_subset_COI <- dna_subset %>% filter(target_gene =="COI")

sequences <- sapply(strsplit(as.character(dna_subset_COI$DNA_sequence), ""), tolower)
names(sequences) <- dna_subset_COI$id
sequences <- ape::as.DNAbin(sequences)
sequences
73 DNA sequences in binary format stored in a list.

Mean sequence length: 300.397 
   Shortest sequence: 200 
    Longest sequence: 313 

Labels:
00197f78-a410-4bd0-bbf9-375d252d5033
001e89fb-008a-482f-89e6-f226d72750d6
002b7cf9-5c46-493c-b87c-437b07b77c1e
002c4bad-af82-422e-86fc-55fe37913d45
008a69f0-8fdd-47b0-9968-b203992442de
008e1ab9-55be-4372-9196-892533ee1836
...

Base composition:
    a     c     g     t 
0.222 0.184 0.190 0.404 
(Total: 21.93 kb)

Now we can align the sequences using MAFFT. The ips (Interfaces to Phylogenetic Software in R) package provides an interface to the MAFFT software.

aligned <- ips::mafft(sequences, method = "auto")
aligned
73 DNA sequences in binary format stored in a matrix.

All sequences of same length: 316 

Labels:
00197f78-a410-4bd0-bbf9-375d252d5033
001e89fb-008a-482f-89e6-f226d72750d6
002b7cf9-5c46-493c-b87c-437b07b77c1e
002c4bad-af82-422e-86fc-55fe37913d45
008a69f0-8fdd-47b0-9968-b203992442de
008e1ab9-55be-4372-9196-892533ee1836
...

Base composition:
    a     c     g     t 
0.222 0.184 0.190 0.404 
(Total: 23.07 kb)

Let’s visualize the aligned sequences:

ape::image.DNAbin(aligned, col=c(RColorBrewer::brewer.pal(6, "Pastel1")), show.bases=T, show.labels=F, base.cex=0.4)

Finally, we can calculate a distance matrix and construct a tree using dist.dna and njs.

distances <- ape::dist.gene(aligned)

tree <- ape::njs(distances) %>%
  left_join(dna_subset %>% select(id, year = date_year, species), by = c("label" = "id"))

ggtree(tree, layout = "circular", cex = 0.3) +
  geom_tiplab(size = 2, aes(label = species, color = year)) +
  scale_color_viridis_c(option = "magma", end = 0.9)

Using the mapper

DNADerivedData extension records can also be included in data downloads from the mapper. To do so, tick the DNADerivedData checkbox in the download confirmation form.

mapper

The resulting archive will include CSV files for the occurrences as well as for the selected extensions. The occurrence and extension tables can be joined using the id column.

mapper

LS0tCnRpdGxlOiAiRE5BRGVyaXZlZERhdGEgZXh0ZW5zaW9uIGRhdGEgYWNjZXNzIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCmF1dGhvcjogIlBpZXRlciBQcm92b29zdCwgU2FhcmEgU3VvbWluZW4iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiNVc2luZyBSIG1hcmtkb3duCgojI1dvcmtpbmcgd2l0aCBSIE1hcmtkb3duCgpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiAKClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDbWQrU2hpZnQrRW50ZXIqLiAKCmBgYHtyfQpwbG90KGNhcnMpCmBgYAoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLiAKClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4KCgojIyBJbnN0YWxsaW5nIHRoZSByb2JpcyBwYWNrYWdlCgpGaXJzdCBpbnN0YWxsIHRoZSBbcm9iaXMgcGFja2FnZV0oaHR0cHM6Ly9naXRodWIuY29tL2lvYmlzL3JvYmlzKS4gSWYgdGhlIHBhY2thZ2UgaXMgYWxyZWFkeSBpbnN0YWxsZWQsIG1ha2Ugc3VyZSB0aGUgdmVyc2lvbiBpcyAyLjEwLjAgb3IgaGlnaGVyLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmlmICghInJvYmlzIiAlaW4lIHJvd25hbWVzKGluc3RhbGxlZC5wYWNrYWdlcygpKSkgewogIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJpb2Jpcy9yb2JpcyIpCn0gZWxzZSBpZiAocGFja2FnZVZlcnNpb24oInJvYmlzIikgPCAiMi4xMC4wIikgewogIGtuaXRyOjprbml0X2V4aXQoKQp9CgpgYGAKCldlIHdpbGwgYWxzbyBuZWVkIHRoZSBmb2xsb3dpbmcgcGFja2FnZXM6CgoKYGBge3J9CmxpYnJhcnkocm9iaXMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShrbml0cikKbGlicmFyeShnZ3RyZWUpCmxpYnJhcnkobWFwdmlldykKbGlicmFyeShzZikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmBgYAoKCgojIGVETkEgZGF0YSBhY2Nlc3MgaW4gT0JJUwoKSW4gdGhpcyBub3RlYm9vayB3ZSB3aWxsIGV4cGxvcmUgZGF0YSBwdWJsaXNoZWQgdG8gT0JJUyB1c2luZyB0aGUgbmV3IFtETkFEZXJpdmVkRGF0YSBleHRlbnNpb25dKGh0dHBzOi8vcnMuZ2JpZi5vcmcvZXh0ZW5zaW9uL2diaWYvMS4wL2RuYV9kZXJpdmVkX2RhdGFfMjAyMS0wNy0wNS54bWwpLiBUaGlzIG5vdGVib29rIGlzIGF2YWlsYWJsZSBhdCBbaHR0cHM6Ly9pb2Jpcy5naXRodWIuaW8vbm90ZWJvb2stZG5hZGVyaXZlZGRhdGEvXShodHRwczovL2lvYmlzLmdpdGh1Yi5pby9ub3RlYm9vay1kbmFkZXJpdmVkZGF0YS8pCgoKIyMgRmluZGluZyBzZXF1ZW5jZSBiYXNlZCBkYXRhCgpCZWZvcmUgd2UgZmV0Y2ggYW55IG9jY3VycmVuY2UgZGF0YSBsZXQncyBmaXJzdCBmaW5kIG91dCB3aGljaCBkYXRhc2V0cyBpbiBPQklTIGFyZSB1c2luZyB0aGUgRE5BRGVyaXZlZERhdGEgZXh0ZW5zaW9uLiBUaGUgYGRhdGFzZXQoKWAgZnVuY3Rpb24gdGFrZXMgbWFueSBvZiB0aGUgc2FtZSBwYXJhbWV0ZXJzIGFzIHRoZSBgb2NjdXJyZW5jZSgpYCBmdW5jdGlvbiwgaW5jbHVkaW5nIGBoYXNleHRlbnNpb25zYCB3aGljaCBhbGxvd3MgdXMgdG8gbGltaXQgb3VyIHNlYXJjaCB0byBvY2N1cnJlbmNlcyB3aGljaCBoYXZlIGxpbmtlZCBleHRlbnNpb24gcmVjb3JkcyBvZiBhIHNwZWNpZmljIHR5cGUuIFBvc3NpYmxlIHZhbHVlcyBpbmNsdWRlIGBNZWFzdXJlbWVudE9yRmFjdGAgYW5kIGBETkFEZXJpdmVkRGF0YWAuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkbmFfZGF0YXNldHMgPC0gZGF0YXNldChoYXNleHRlbnNpb25zID0gIkROQURlcml2ZWREYXRhIikKCmRuYV9kYXRhc2V0cyAlPiUKICBzZWxlY3QodXJsLCB0aXRsZSwgcmVjb3JkcykgJT4lCiAga2FibGUoKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKZG5hX2RhdGFzZXRzX2dlbzwtZG5hX2RhdGFzZXRzJGV4dGVudFshaXMubmEoZG5hX2RhdGFzZXRzJGV4dGVudCldCgplZG5hX3BvbHlnb25zIDwtIHN0X2FzX3NmYyhkbmFfZGF0YXNldHNfZ2VvLCBjcnMgPSA0MzI2KQoKbWFwdmlldyhlZG5hX3BvbHlnb25zKQoKYGBgCiNJbiBjYXNlIG9mIGVycm9yIHRyeSBzZXR0aW5nOiAKI21hcHZpZXdPcHRpb25zKGZnYiA9IEZBTFNFKQoKCgojIyBGZXRjaGluZyBzZXF1ZW5jZSBiYXNlZCBkYXRhCgpMZXQncyBmZXRjaCBhbGwgb2NjdXJyZW5jZXMgZnJvbSB0aGUgUGFjTUFOIGRhdGFzZXQgYnkgdXNpbmcgdGhlIGBkYXRhc2V0aWRgIHBhcmFtZXRlci4gQWx0ZXJuYXRpdmVseSwgc2V0IGBoYXNleHRlbnNpb25zYCB0byBgRE5BRGVyaXZlZERhdGFgLiBBbHNvIHNldCB0aGUgYGV4dGVuc2lvbnNgIHBhcmFtZXRlciB0byBlbnN1cmUgdGhhdCB0aGUgbmVzdGVkIGV4dGVuc2lvbiByZWNvcmRzIGFyZSBpbmNsdWRlZCBpbiB0aGUgcmVzdWx0cy4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwYWNtYW5JRDwtZG5hX2RhdGFzZXRzICU+JSBmaWx0ZXIoZ3JlcGwoIlBhY01BTiIsIHRpdGxlKSklPiUKc2VsZWN0KGlkKQoKb2NjIDwtIG9jY3VycmVuY2UoZGF0YXNldGlkID0gcGFjbWFuSUQsIGV4dGVuc2lvbnMgPSAiRE5BRGVyaXZlZERhdGEiLCB3cmltcyA9IFQpCm9jYwpgYGAKCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSB0YXhvbm9taWMgY29tcG9zaXRpb24gb2Ygb3VyIGRhdGFzZXQ6CgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kb2NjICU+JQogIGdyb3VwX2J5KHBoeWx1bSkgJT4lCiAgc3VtbWFyaXplKHNwZWNpZXMgPSBsZW5ndGgodW5pcXVlKHNwZWNpZXNpZCkpLCByZWNvcmRzID0gbigpKSAlPiUKICBhcnJhbmdlKGRlc2Moc3BlY2llcykpCmBgYAoKIyMgRXh0cmFjdGluZyBETkFEZXJpdmVkRGF0YSByZWNvcmRzCgpUaGUgRE5BRGVyaXZlZERhdGEgcmVjb3JkcyBhcmUgY3VycmVudGx5IG5lc3RlZCB3aXRoaW4gdGhlIG9jY3VycmVuY2VzIHdlIGZldGNoZWQgZnJvbSBPQklTLiBUbyBleHRyYWN0IHRoZSBleHRlbnNpb24gcmVjb3JkcyB3ZSBjYW4gdXNlIHRoZSBgdW5uZXN0X2V4dGVuc2lvbigpYCBmdW5jdGlvbi4gUGFzcyBhbnkgZmllbGRzIGZyb20gdGhlIG9jY3VycmVuY2UgdGFibGUgeW91IHdvdWxkIGxpa2UgdG8ga2VlcCB1c2luZyB0aGUgYGZpZWxkc2AgcGFyYW1ldGVyLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRuYSA8LSB1bm5lc3RfZXh0ZW5zaW9uKG9jYywgIkROQURlcml2ZWREYXRhIiwgZmllbGRzID0gYygiaWQiLCAicGh5bHVtIiwgImNsYXNzIiwgIm9yZGVyIiwgImZhbWlseSIsICJnZW51cyIsICJzcGVjaWVzIiwgImRhdGVfeWVhciIpKQpkbmEgJT4lIHNlbGVjdCh3aGVyZSh+c3VtKCFpcy5uYSguKSkgPiAwKSkKYGBgCgpMZXQncyB0YWtlIGEgbG9vayBhdCBzb21lIHByb3BlcnRpZXMgb2YgdGhlIHNlcXVlbmNlIHJlY29yZHMuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZG5hICU+JQogIGdyb3VwX2J5KHRhcmdldF9nZW5lLCBwY3JfcHJpbWVyX25hbWVfZm9yd2FyZCwgcGNyX3ByaW1lcl9uYW1lX3JldmVyc2UpICU+JQogIHN1bW1hcml6ZShyZWNvcmRzID0gbigpKSAlPiUKICBrYWJsZSgpCmBgYAoKIyMgV29ya2luZyB3aXRoIEROQURlcml2ZWREYXRhIHJlY29yZHMKClRoaXMgaXMgYSBxdWljayBkZW1vIG9mIHdvcmtpbmcgd2l0aCBzZXF1ZW5jZXMgZnJvbSB0aGUgRE5BRGVyaXZlZERhdGEgZXh0ZW5zaW9uLiBGb3IgdGhlIHJlbWFpbmRlciBvZiB0aGUgbm90ZWJvb2sgSSB3aWxsIHdvcmsgd2l0aCBhIHN1YnNldCBvZiB0aGUgc2VxdWVuY2UgZGF0YS4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkbmFfc3Vic2V0IDwtIGRuYSAlPiUKICBmaWx0ZXIocGh5bHVtID09ICJDaG9yZGF0YSIgJiAhaXMubmEoc3BlY2llcykpICU+JQogIGhlYWQoMTAwKQoKYGBgCgpUbyBiZSBhYmxlIHRvIG1ha2UgdXNlIG9mIGV4aXN0aW5nIGJpb2luZm9ybWF0aWNzIHBhY2thZ2VzIHdlIGZpcnN0IG5lZWQgdG8gY29udmVydCBvdXIgYEROQV9zZXF1ZW5jZWAgY29sdW1uIHRvIGEgYEROQWJpbmAgb2JqZWN0LiBUaGlzIGNhbiBiZSBkb25lIHVzaW5nIGBhcy5ETkFiaW5gIGZ1bmN0aW9uIGZyb20gdGhlIGBhcGVgIChBbmFseXNlcyBvZiBQaHlsb2dlbmV0aWNzIGFuZCBFdm9sdXRpb24pIHBhY2thZ2UuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKZG5hX3N1YnNldF9DT0kgPC0gZG5hX3N1YnNldCAlPiUgZmlsdGVyKHRhcmdldF9nZW5lID09IkNPSSIpCgpzZXF1ZW5jZXMgPC0gc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3RlcihkbmFfc3Vic2V0X0NPSSRETkFfc2VxdWVuY2UpLCAiIiksIHRvbG93ZXIpCm5hbWVzKHNlcXVlbmNlcykgPC0gZG5hX3N1YnNldF9DT0kkaWQKc2VxdWVuY2VzIDwtIGFwZTo6YXMuRE5BYmluKHNlcXVlbmNlcykKc2VxdWVuY2VzCgpgYGAKCk5vdyB3ZSBjYW4gYWxpZ24gdGhlIHNlcXVlbmNlcyB1c2luZyBNQUZGVC4gVGhlIGBpcHNgIChJbnRlcmZhY2VzIHRvIFBoeWxvZ2VuZXRpYyBTb2Z0d2FyZSBpbiBSKSBwYWNrYWdlIHByb3ZpZGVzIGFuIGludGVyZmFjZSB0byB0aGUgTUFGRlQgc29mdHdhcmUuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQphbGlnbmVkIDwtIGlwczo6bWFmZnQoc2VxdWVuY2VzLCBtZXRob2QgPSAiYXV0byIpCmFsaWduZWQKYGBgCgpMZXQncyB2aXN1YWxpemUgdGhlIGFsaWduZWQgc2VxdWVuY2VzOgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYXBlOjppbWFnZS5ETkFiaW4oYWxpZ25lZCwgY29sPWMoUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDYsICJQYXN0ZWwxIikpLCBzaG93LmJhc2VzPVQsIHNob3cubGFiZWxzPUYsIGJhc2UuY2V4PTAuNCkKYGBgCgpGaW5hbGx5LCB3ZSBjYW4gY2FsY3VsYXRlIGEgZGlzdGFuY2UgbWF0cml4IGFuZCBjb25zdHJ1Y3QgYSB0cmVlIHVzaW5nIGBkaXN0LmRuYWAgYW5kIGBuanNgLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGlzdGFuY2VzIDwtIGFwZTo6ZGlzdC5nZW5lKGFsaWduZWQpCgp0cmVlIDwtIGFwZTo6bmpzKGRpc3RhbmNlcykgJT4lCiAgbGVmdF9qb2luKGRuYV9zdWJzZXQgJT4lIHNlbGVjdChpZCwgeWVhciA9IGRhdGVfeWVhciwgc3BlY2llcyksIGJ5ID0gYygibGFiZWwiID0gImlkIikpCgpnZ3RyZWUodHJlZSwgbGF5b3V0ID0gImNpcmN1bGFyIiwgY2V4ID0gMC4zKSArCiAgZ2VvbV90aXBsYWIoc2l6ZSA9IDIsIGFlcyhsYWJlbCA9IHNwZWNpZXMsIGNvbG9yID0geWVhcikpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2Mob3B0aW9uID0gIm1hZ21hIiwgZW5kID0gMC45KQoKYGBgCgojIFVzaW5nIHRoZSBtYXBwZXIKCkROQURlcml2ZWREYXRhIGV4dGVuc2lvbiByZWNvcmRzIGNhbiBhbHNvIGJlIGluY2x1ZGVkIGluIGRhdGEgZG93bmxvYWRzIGZyb20gdGhlIFttYXBwZXJdKGh0dHBzOi8vbWFwcGVyLm9iaXMub3JnLykuIFRvIGRvIHNvLCB0aWNrIHRoZSBETkFEZXJpdmVkRGF0YSBjaGVja2JveCBpbiB0aGUgZG93bmxvYWQgY29uZmlybWF0aW9uIGZvcm0uCgohW21hcHBlcl0oaW1hZ2VzL21hcHBlci5wbmcpCgpUaGUgcmVzdWx0aW5nIGFyY2hpdmUgd2lsbCBpbmNsdWRlIENTViBmaWxlcyBmb3IgdGhlIG9jY3VycmVuY2VzIGFzIHdlbGwgYXMgZm9yIHRoZSBzZWxlY3RlZCBleHRlbnNpb25zLiBUaGUgb2NjdXJyZW5jZSBhbmQgZXh0ZW5zaW9uIHRhYmxlcyBjYW4gYmUgam9pbmVkIHVzaW5nIHRoZSBgaWRgIGNvbHVtbi4KCiFbbWFwcGVyXShpbWFnZXMvZG93bmxvYWQucG5nKQoKCg==